#include "core/config/mixp_config.h"
#include "gear-lib/libdebug.h"

#include "mixedprocess.h"
#include "process/mixp_master.h"

#include <signal.h>

#include <sys/syscall.h>
#define gettid() syscall(__NR_gettid)

static char *mixp_conf_file = MIXP_CONF_PATH;
static mixp_uint_t need_mixp_show_help;

static int mixp_show_help(void);
static mixp_uint_t mixp_get_options(int argc, char const *argv[]);
static int mixp_init_logger(struct mixp_config *);
static void on_sig_int(int);

int main(int argc, char const *argv[])
{
    debug_backtrace_init();

    if (mixp_get_options(argc, argv) != MIXP_OK)
    {
        return MIXP_ERROR;
    }

    if (need_mixp_show_help)
    {
        return mixp_show_help();
    }

    mixp_config_t *conf = mixp_conf_load(mixp_conf_file);
    if (!conf)
        return MIXP_ERROR;

    mixp_init_logger(conf);

    if (mixp_master_init(conf) == 0)
    {
        signal(SIGINT, on_sig_int);

        mixp_master_run();
        mixp_master_free();
    }
    else
    {
        loge("start master failed.");
        return MIXP_ERROR;
    }

    log_deinit();
    mixp_conf_unload(conf);

    return MIXP_OK;
}

static mixp_uint_t mixp_get_options(int argc, char const *argv[])
{
    char *p;
    mixp_int_t i;

    for (i = 1; i < argc; i++)
    {
        p = (char *)argv[i];
        if (*p++ != '-')
        {
            fprintf(stderr, "invalid option: \"%s\"\n", argv[i]);
            return MIXP_ERROR;
        }

        while (*p)
        {
            switch (*p++)
            {
            case '?':
            case 'h':
                need_mixp_show_help = 1;
                break;
            case 'c':
                if (*p)
                {
                    mixp_conf_file = p;
                    goto next;
                }

                if (argv[++i])
                {
                    mixp_conf_file = (char *)argv[i];
                    goto next;
                }

                return MIXP_ERROR;
            default:
                fprintf(stderr, "invalid option 2: \"%s\"\n", argv[i]);
                return MIXP_ERROR;
            }
        }
    next:
        continue;
    }

    return MIXP_OK;
}

static int mixp_show_help(void)
{
    fprintf(
        stderr,
        "Usage: mixedprocess [-?h] [-c filename]" MIXP_LINEFEED
        "Options:" MIXP_LINEFEED
        "  -c filename   : set configuration file (default: " MIXP_CONF_PATH
        ")" MIXP_LINEFEED);

    return MIXP_OK;
}

static int mixp_logger_level_by_char(char *plevel)
{
    int level = LOG_VERB;

    if (plevel != NULL)
    {
        switch (*plevel)
        {
        case 'c':
        case 'C':
            level = LOG_CRIT;
            break;
        case 'd':
        case 'D':
            level = LOG_DEBUG;
            break;
        case 'e':
        case 'E':
            level = LOG_ERR;
            break;
        case 'n':
        case 'N':
            level = LOG_NOTICE;
            break;
        case 'v':
        case 'V':
            level = LOG_VERB;
            break;
        case 'w':
        case 'W':
            level = LOG_WARNING;
            break;

        default:
            level = LOG_INFO;
            break;
        }
    }

    return level;
}

static int mixp_init_logger(struct mixp_config *conf)
{
    int level = mixp_logger_level_by_char(mixp_conf_get_string(conf, "log.level"));

    char *filename = mixp_conf_get_string(conf, "log.filename");
    if (filename && strlen(filename) > 0)
    {
        log_init(LOG_FILE, filename);

        int filelength = mixp_conf_get_int(conf, "log.filelength");
        if (filelength > 0)
            log_set_split_size(filelength);
    }

    log_set_level(level);

    return level;
}

static void on_sig_int(int signum)
{
    logw("received SIGINT, begin stopping...");
    mixp_master_stop();
}
